package com.blb.netty.zbcb;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.channel.*;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.DelimiterBasedFrameDecoder;
import io.netty.handler.codec.FixedLengthFrameDecoder;
import io.netty.handler.codec.LineBasedFrameDecoder;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.util.concurrent.GlobalEventExecutor;

import java.nio.ByteBuffer;
import java.util.Iterator;

/**
 * 聊天室服务器
 */
public class ChatroomServer {

    public void start(){
        System.out.println("启动聊天室服务器");
        //创建boss线程组，用于接收客户端
        NioEventLoopGroup bossGroup = new NioEventLoopGroup(2);
        //创建工作线程组，用于服务客户端
        NioEventLoopGroup workGroup = new NioEventLoopGroup(10);
        try {
            //创建服务器启动对象
            ServerBootstrap serverBootstrap = new ServerBootstrap();
            //配置启动对象
            serverBootstrap.group(bossGroup,workGroup)          //设置线程组
                    .option(ChannelOption.SO_BACKLOG,100) //客户端队列长度
                    .channel(NioServerSocketChannel.class)      //设置通道类型
                    .childHandler(new ChannelInitializer<SocketChannel>() { //设置通道的处理器
                        @Override
                        protected void initChannel(SocketChannel socketChannel) throws Exception {
                            socketChannel.pipeline()  //设置管道
//                                    .addLast(new LineBasedFrameDecoder(100))
//                                    .addLast(new DelimiterBasedFrameDecoder(100, B))
                                    .addLast(new FixedLengthFrameDecoder("测试一下！！".getBytes().length))
                                    .addLast(new StringDecoder()) //字符串解码器 byte-->string
                                    .addLast(new StringEncoder()) //字符串编码器 string-->byte
                                    .addLast(new ChatroomServerHandler());               //自定义处理器
                        }
                    });
            //绑定端口 sync 同步化
            ChannelFuture sync = serverBootstrap.bind("192.168.114.22", 6666).sync();
            //让通道使用完后关闭
            sync.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            //关闭线程组
            bossGroup.shutdownGracefully();
            workGroup.shutdownGracefully();
        }
    }

    /**
     * 聊天室处理器
     */
    static class ChatroomServerHandler extends SimpleChannelInboundHandler<String> {

        //创建通道组用于保存所有的客户端通道
        private static ChannelGroup channels = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);

        //读取客户端
        @Override
        protected void channelRead0(ChannelHandlerContext ctx, String s) throws Exception {
            System.out.println(ctx.channel().remoteAddress() + "说:" + s);
            String ips = "";
            Iterator<Channel> iterator = channels.iterator();
            while (iterator.hasNext()){
                Channel channel = iterator.next();
                ips += channel.remoteAddress().toString() + ",";
            }
            System.out.println("在线用户：" + ips);
            //读取消息后群发给所有人
            channels.writeAndFlush(ctx.channel().remoteAddress() + "说:" + s);
        }

        //客户端上线
        @Override
        public void channelActive(ChannelHandlerContext ctx) throws Exception {
            System.out.println(ctx.channel().remoteAddress() + "上线了");
            //加到线程组
            channels.add(ctx.channel());
            //广播上线消息
            channels.writeAndFlush(ctx.channel().remoteAddress() + "上线了");
        }

        //客户端下线
        @Override
        public void channelInactive(ChannelHandlerContext ctx) throws Exception {
            System.out.println(ctx.channel().remoteAddress() + "下线了");
            //删除通道
            channels.remove(ctx.channel());
            //广播下线消息
            channels.writeAndFlush(ctx.channel().remoteAddress() + "下线了");
        }

        //客户端异常
        @Override
        public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
            ctx.close();
        }
    }

    public static void main(String[] args) {
        new ChatroomServer().start();
    }
}
